package com.app.reptile.utils;

import com.alibaba.druid.support.monitor.annotation.MField;
import com.alibaba.druid.support.monitor.annotation.MTable;
import com.alibaba.druid.util.JdbcUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * CatTableUtils 表监测工具
 */
public class CatTableUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(CatTableUtils.class);

    public static boolean isCreateCatTable(Class<?> clazz, Connection connection){
        boolean sure = false;
        try {
            MTable table = clazz.getAnnotation(MTable.class);
            if (Objects.nonNull(table) && StringUtils.isBlank(table.name()) || Objects.isNull(table)){
                return false;
            }
            StringBuilder stringBuilder = new StringBuilder("select count(*) cnt from ");
            stringBuilder.append(table.name());
            Integer cnt = 0;
            try{

                List<Map<String,Object>> list = JdbcUtils.executeQuery(connection,stringBuilder.toString(),new ArrayList<>());

                for(Map<String,Object> map : list){
                    if (!cnt.equals(map.get("cnt"))){
                        sure = true;
                        break;
                    }
                }
            }catch (Exception e){
                LOGGER.error("查询{} 失败",table.name(),e);
            }
            if (!sure){
                //自动创建表
                StringBuilder builder = new StringBuilder("CREATE TABLE ");
                builder.append(table.name());
                builder.append(" ( ");

                for(int index = 0; index < clazz.getDeclaredFields().length; index ++){

                    Field field = clazz.getDeclaredFields()[index];
                    MField mField = field.getAnnotation(MField.class);
                    if (Objects.nonNull(mField)){
                        builder.append(mField.name());
                        builder.append(" ");
                        builder.append(mField.hashForType());
                        builder.append(", ");
                    }
                }
                builder.append(" )");

                for(int index = builder.length() - 1; index >= 0; index --){
                    if (builder.charAt(index) == ','){
                        builder.deleteCharAt(index);
                        break;
                    }
                }
                try {
                    JdbcUtils.execute(connection,builder.toString());
                } catch (SQLException e) {
                    LOGGER.error("创建{} 失败",builder.toString(),e);
                }
            }
        }finally {
            JdbcUtils.close(connection);
        }

        return sure;
    }


    public static void insertData(Class<?> clazz,Connection connection,Object bean) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, SQLException {
        try{
            if (Objects.nonNull(bean)){
                MTable table = clazz.getAnnotation(MTable.class);

                StringBuilder builder = new StringBuilder("insert into ");
                builder.append(table.name());
                builder.append(" (");
                List<Object> values = new ArrayList<>();
                List<String> keys = new ArrayList<>();
                List<String> vs = new ArrayList<>();

                if (bean.getClass().equals(clazz)){
                    for(int index = 0; index < clazz.getDeclaredFields().length; index ++){
                        Field field = clazz.getDeclaredFields()[index];
                        MField mField = field.getAnnotation(MField.class);
                        if (Objects.nonNull(mField)){
                            Object value = PropertyUtils.getProperty(bean,field.getName());
                            if (Objects.nonNull(value)){
                                values.add(value);
                                keys.add(mField.name());
                                vs.add("?");
                            }
                        }
                    }
                }

                if (keys.size() > 0){
                    builder.append(String.join(",",keys));
                    builder.append(" ) VALUES ( ");
                    builder.append(String.join(",",vs));
                    builder.append(" )");
                    JdbcUtils.execute(connection,builder.toString(),values);
                }
            }
        }finally {
            JdbcUtils.close(connection);
        }

    }

    public static <T>  void insertDataList(Class<?> clazz,Connection connection,List<T> beans) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, SQLException {
        try{
            if (Objects.nonNull(beans)){
                MTable table = clazz.getAnnotation(MTable.class);

                StringBuilder builder = new StringBuilder("insert into ");
                builder.append(table.name());
                List<String> keys = getKeys(clazz);
                builder.append(" (");
                builder.append( String.join(",",keys));
                builder.append(")");
                builder.append(" VALUES ");

                List<Object> values = new ArrayList<>();

                List<String> vsList = new ArrayList<>();
                for(Object bean : beans){
                    StringBuilder stringBuilder = new StringBuilder();
                    stringBuilder.append(" ( ");
                    List<String> vs = new ArrayList<>();
                    for(int index = 0; index < clazz.getDeclaredFields().length; index ++){
                        Field field = clazz.getDeclaredFields()[index];
                        MField mField = field.getAnnotation(MField.class);
                        if (Objects.nonNull(mField)){
                            Object value = PropertyUtils.getProperty(bean,field.getName());
                            values.add(value);
                            vs.add("?");
                        }
                    }

                    stringBuilder.append(String.join(",",vs));
                    stringBuilder.append(" )");
                    vsList.add(stringBuilder.toString());
                }

                builder.append(String.join(",",vsList));
                if (keys.size() > 0){
                    JdbcUtils.execute(connection,builder.toString(),values);
                }
            }
        }finally {
            JdbcUtils.close(connection);
        }

    }


    private static List<String> getKeys(Class<?> clazz){
        List<String> keys = new ArrayList<>();

        for(int index = 0; index < clazz.getDeclaredFields().length; index ++){
            Field field = clazz.getDeclaredFields()[index];
            MField mField = field.getAnnotation(MField.class);
            if (Objects.nonNull(mField) && StringUtils.isNotBlank(mField.name())){
                keys.add(mField.name());
            }
        }
        return keys;
    }

    public static <T> List<T> selectData(Class<?> clazz,Connection connection) throws IllegalAccessException, InstantiationException, InvocationTargetException, SQLException, NoSuchMethodException {
        List<T> result = new ArrayList<>();
        try{
            MTable table = clazz.getAnnotation(MTable.class);

            StringBuilder builder = new StringBuilder("select ");
            List<String> keys = getKeys(clazz);

            if (keys.size() == 0){
                return result;
            }
            builder.append(String.join(",",keys));
            builder.append(" from ");
            builder.append(table.name());
            List<Map<String,Object>> list = JdbcUtils.executeQuery(connection,builder.toString(),new ArrayList<>());
            selectList(clazz, result, list);
        }finally {
            JdbcUtils.close(connection);
        }
        return result;
    }


    public static <T> List<T> selectData(Class<?> clazz,Connection connection,String sql) throws IllegalAccessException, InstantiationException, InvocationTargetException, SQLException, NoSuchMethodException {
        List<T> result = new ArrayList<>();
        try{
            List<Map<String,Object>> list = JdbcUtils.executeQuery(connection,sql,new ArrayList<>());
            selectList(clazz, result, list);
        }finally {
            JdbcUtils.close(connection);
        }
        return result;
    }


    private static <T> void selectList(Class<?> clazz, List<T> result, List<Map<String,Object>> list) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        for(Map<String,Object> map : list){
            Object obj = clazz.newInstance();

            for(int index = 0; index < clazz.getDeclaredFields().length; index ++){
                Field field = clazz.getDeclaredFields()[index];
                MField mField = field.getAnnotation(MField.class);
                if (Objects.nonNull(mField) && StringUtils.isNotBlank(mField.name())){
                    BeanUtils.setProperty(obj,field.getName(),BeanUtils.getProperty(map, mField.name()));
                }
            }
            result.add((T)obj);
        }
    }
}
